/******************************************************
*  Copyright(c) pages.ilovezxl.top
*  FileName : util.h
*  Author : rivulet.dave
*  Description : ¹«¹²º¯Êý
*  Data : 2019-04-15
******************************************************/


/*********************************************************************
 * INCLUDES
 */

#include "stdrope.h"
#include "util.h"

/*********************************************************************
 * TYPES
 */

/*********************************************************************
 * MACROS
 */

#define BAD    -1

#define POLY 0xEDB88320L		//the crc32 is the same with WINRAR

/*********************************************************************
 * FUNCTIONS DECLARE
 */

/*********************************************************************
 *  VARIABLES
 */

static uint32_t   auiCrc32[256];    //crc32


static const char base64digits[] = /* characters used for base64 code */
                                   "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static const int8_t base64val[] =  /* base64 alphabet */
{
    BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
    BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
    BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,  62, BAD, BAD, BAD,  63,
    52,   53,  54,  55,  56,  57,  58,  59,  60,  61, BAD, BAD, BAD, BAD, BAD, BAD,
    BAD,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,
    15,   16,  17,  18,  19,  20,  21,  22,  23,  24,  25, BAD, BAD, BAD, BAD, BAD,
    BAD,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,
    41,   42,  43,  44,  45,  46,  47,  48,  49,  50,  51, BAD, BAD, BAD, BAD, BAD
};

#define ENCODE64(c)    (((c) & 0xC0) ? BAD : base64digits[(int)c])
#define DECODE64(c)    (((c) & 0x80) ? BAD : base64val[(int)c])

/*********************************************************************
 * FUNCTIONS
 */

/**
 *   @Description: ×Ö·û´®×ªBCDÂë - Ð¡¶ËÐò£ºÏÈµÍ4Î»£¬ºó¸ß4Î»
 *   @param *puiDest - BCDÂë´æ·ÅµÄÄ¿µÄµØÖ·.
 *   @param *pSrc - ×Ö·û´®µØÖ·.
 *   @return £ºBCDÂëµÄ³¤¶È
 */
uint32_t UTL_Str2BCDLittle(uint8_t *puiDest, const char *pSrc)
{
    uint32_t i;
    uint8_t  hbit, lbit;
    uint32_t uiLen = strlen(pSrc);

    for (i = 0; i < uiLen; i += 2)
    {
        /* µÍ4Î» */
        lbit = (pSrc[i] > '9') ? (uint8_t)((pSrc[i] & 0x0F) + 9) : (pSrc[i] & 0x0F);

        /* ¸ß4Î»£¬Èç¹ûÃ»ÓÐÔò²¹F */
        if (0x00 == pSrc[i + 1])
        {
            hbit = 0x0F;
        }
        else
        {
            hbit = (pSrc[i + 1] > '9') ? (uint8_t)((pSrc[i + 1] & 0x0F) + 9) : (pSrc[i + 1] & 0x0F);
        }

        puiDest[i / 2] = (hbit << 4) | lbit;
    }

    return (uiLen + 1) / 2;
}


/**
 *   @Description: BCDÂë×ª×Ö·û´® - Ð¡¶ËÐò£ºÏÈµÍ4Î»£¬ºó¸ß4Î»
 *   @param *pDest - ×Ö·û´®µØÖ·.
 *   @param *puiSrc - BCDÂë´æ·ÅµÄµØÖ·.
 *   @param uiSrcLen - BCDÂëµÄ³¤¶È.
 *   @return £ºNA
 */
void UTL_BCD2StrLittle(char *pDest, const uint8_t *puiSrc, uint32_t uiSrcLen)
{
    uint8_t    uiTemp           = 0;
    const char uiBCD2AsciiTbl[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

    for (uint32_t i = 0; i < uiSrcLen; i++)
    {
        /* µÍ4Î» */
        uiTemp   = puiSrc[i] & 0x0F;
        *pDest++ = uiBCD2AsciiTbl[uiTemp];

        /* ¸ß4Î» */
        uiTemp   = puiSrc[i] >> 4;
        *pDest++ = uiBCD2AsciiTbl[uiTemp];
    }

    *pDest = 0;
}


/**
 *   @Description: ×Ö·û´®×ªBCDÂë
 *   @param *puiDest - BCDÂë´æ·ÅµÄÄ¿µÄµØÖ·.
 *   @param *pSrc - ×Ö·û´®µØÖ·.
 *   @return £ºBCDÂëµÄ³¤¶È
 */
uint32_t UTL_Str2BCD(uint8_t *puiDest, const char *pSrc)
{
    uint32_t i;
    uint8_t  hbit, lbit;
    uint32_t uiLen = strlen(pSrc);

    for (i = 0; i < uiLen; i += 2)
    {
        /* ¸ß4Î» */
        hbit = (pSrc[i] > '9') ? (uint8_t)((pSrc[i] & 0x0F) + 9) : (pSrc[i] & 0x0F);

        /* µÍ4Î»£¬Èç¹ûÃ»ÓÐÔò²¹F */
        if (0x00 == pSrc[i + 1])
        {
            lbit = 0x0F;
        }
        else
        {
            lbit = (pSrc[i + 1] > '9') ? (uint8_t)((pSrc[i + 1] & 0x0F) + 9) : (pSrc[i + 1] & 0x0F);
        }

        puiDest[i / 2] = (hbit << 4) | lbit;
    }

    return (uiLen + 1) / 2;
}


/**
 *   @Description: BCDÂë×ª×Ö·û´®
 *   @param *pDest - ×Ö·û´®µØÖ·.
 *   @param *puiSrc - BCDÂë´æ·ÅµÄµØÖ·.
 *   @param uiSrcLen - BCDÂëµÄ³¤¶È.
 *   @return £ºNA
 */
void UTL_BCD2Str(char *pDest, const uint8_t *puiSrc, uint32_t uiSrcLen)
{
    UTL_Hex2Str(pDest, puiSrc, uiSrcLen);
}


/**
 *   @Description: 16½øÖÆ×ª×Ö·û´®
 *   @param *pDest - ×Ö·û´®µØÖ·.
 *   @param *puiSrc - 16½øÖÆÊý¾Ý.
 *   @param uiSrcLen - 16½øÖÆÊý¾Ý³¤¶È.
 *   @return £ºNA
 */
void UTL_Hex2Str(char *pDest, const uint8_t *puiSrc, uint32_t uiSrcLen)
{
    uint8_t    uiTemp           = 0;
    const char uiBCD2AsciiTbl[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

    for (uint32_t i = 0; i < uiSrcLen; i++)
    {
        /* ¸ß4Î» */
        uiTemp   = puiSrc[i] >> 4;
        *pDest++ = uiBCD2AsciiTbl[uiTemp];

        /* µÍ4Î» */
        uiTemp   = puiSrc[i] & 0x0F;
        *pDest++ = uiBCD2AsciiTbl[uiTemp];
    }

    *pDest = 0;
}


/**
 *   @Description: ×Ö·û´®×ª16½øÖÆ
 *   @param *pDest - 16½øÖÆÊý¾Ý.
 *   @param *puiSrc - ×Ö·û´®µØÖ·.
 *   @return £º16½øÖÆÊý¾Ý³¤¶È
 */
uint32_t UTL_Str2Hex(uint8_t *puiDest, const char *pSrc)
{
    uint32_t i;
    uint8_t  hbit, lbit;
    int      uiLen = strlen(pSrc);

    if (uiLen % 2)
    {
        return 0;
    }

    for (i = 0; i < uiLen; i += 2)
    {
        /* ¸ß4Î» */
        hbit = (pSrc[i] > '9') ? ((pSrc[i] & 0x0F) + 9) : (pSrc[i] & 0x0F);

        /* µÍ4Î» */
        lbit = (pSrc[i + 1] > '9') ? ((pSrc[i + 1] & 0x0F) + 9) : (pSrc[i + 1] & 0x0F);

        puiDest[i / 2] = (hbit << 4) | lbit;
    }

    return uiLen / 2;
}


/**
 *
 */
int32_t UTL_Str2Int(char *pSrc)
{
    return atoi(pSrc);
}


/**
 *
 *
 */
char *UTL_Int2Str(char *pDest, int32_t iSrc)
{
    uint32_t uiPower = 0;
    int32_t iNum = iSrc;
    char *pTemp = pDest;

    if (0 > iNum)
    {
        iNum = 0 - iNum;
        *pTemp++ = '-';
    }

    for (uiPower = 1; iNum > 10; iNum /= 10)
    {
        uiPower *= 10;
    }

    iNum = (iSrc > 0)?iSrc:0 - iSrc;
    for (; uiPower > 0; uiPower /= 10)
    {
        *pTemp++ = iNum / uiPower + '0';
        iNum %= uiPower;
    }
    *pTemp = '\0';

    return pDest;
}


/**
 *   @Description: °´×Ö½Ú¼ÆËãÒì»òÐ£ÑéÂë
 *   @param *pucData - 16½øÖÆÊý¾Ý.
 *   @param *uiLen - ×Ö·û´®µØÖ·.
 *   @return £ºÒì»òÐ£ÑéÂë
 */
uint8_t UTL_CalcByteXORCheckSum(uint8_t *pucData, uint32_t uiLen)
{
    uint8_t uiCheckCode = 0;

    for (uint32_t i = 0; i < uiLen; i++)
    {
        uiCheckCode ^= pucData[i];
    }

    return uiCheckCode;
}


/*************************************************
*  Function:       base64_to_ascii
*  Description:    decodes string from base64 to ascii
*  Input:          const char *in: the input string (NIL-terminated)
*  int inlen: length of input string
*  int maxlen: the output buffer size limit, 0 to ignore
*  Output:         unsigned char *out: decoded output string
*  Return:         length of output string on successful
*  less than 0 on error occur, then the output is invalid
*  Others:
*************************************************/
int32_t UTL_Base64Decode(uint8_t *out, uint8_t *in, int32_t inlen, int32_t maxlen)
{
    int32_t         outlen = 0;
    int32_t         over = 0; /* decode over flag */
    register int8_t digit0, digit1, digit2, digit3;
    uint8_t        *out_org = out;

    /* check if arguments valid */
    if (!out || !in)
    {
        return UTL_BASE64_INVALID_ARG;
    }

    memset(out, 0x00, maxlen);

    /* decode each four base64 characters */
    for ( ; inlen >= 4; inlen -= 4, in += 4)
    {
        /* update output length and check overflow */
        if ((++outlen >= maxlen) && maxlen)
        {
            *out_org = '\0';
            return UTL_BASE64_OUTPUT_OVERFLOW;
        }

        if ((digit0 = DECODE64(in[0])) == BAD)
        {
            *out_org = '\0';
            return UTL_BASE64_WRONG_FORMAT;
        }

        if ((digit1 = DECODE64(in[1])) == BAD)
        {
            *out_org = '\0';
            return UTL_BASE64_WRONG_FORMAT;
        }
        *out++ = ((digit0 << 2) & 0xFC) | ((digit1 >> 4) & 0x03);

        if (in[2] != '=')
        {
            /* update output length and check overflow */
            if ((++outlen >= maxlen) && maxlen)
            {
                *out_org = '\0';
                return UTL_BASE64_OUTPUT_OVERFLOW;
            }

            if ((digit2 = DECODE64(in[2])) == BAD)
            {
                *out_org = '\0';
                return UTL_BASE64_WRONG_FORMAT;
            }
            *out++ = ((digit1 << 4) & 0xF0) | ((digit2 >> 2) & 0x0F);

            if (in[3] != '=')
            {
                /* update output length and check overflow */
                if ((++outlen >= maxlen) && maxlen)
                {
                    *out_org = '\0';
                    return UTL_BASE64_OUTPUT_OVERFLOW;
                }

                if ((digit3 = DECODE64(in[3])) == BAD)
                {
                    *out_org = '\0';
                    return UTL_BASE64_WRONG_FORMAT;
                }
                *out++ = ((digit2 << 6) & 0xC0) | (digit3 & 0x3F);
            }
            else
            {
                over = 1;
                break;
            }
        }
        else
        {
            over = 1;
            break;
        }
    }

    /* there cannt have tail-fragment except after '=' */
    if (!over && (inlen > 0))
    {
        *out_org = '\0';
        return UTL_BASE64_WRONG_FORMAT;
    }

    /* terminate the output string */
    *out = '\0';

    return outlen;
}


/*************************************************
*  Function:       ascii_to_base64
*  Description:    encodes string from ascii to base64
*  Input:          const char *in: the input string (NIL-terminated)
*  int inlen: length of input string
*  int maxlen: the output buffer size limit, 0 to ignore
*  Output:         unsigned char *out: decoded output string
*  Return:         length of output string on successful
*  less than 0 on error occur, then the output is invalid
*  Others:
*************************************************/
int32_t UTL_Base64Encode(int8_t *out, const uint8_t *in, int32_t inlen, int32_t maxlen)
{
    int32_t outlen  = 0;
    int8_t *out_org = out;

    /* check if arguments valid */
    if (!out || !in)
    {
        return UTL_BASE64_INVALID_ARG;
    }

    memset(out, 0x00, maxlen);

    /* encode each three ascii characters */
    for ( ; inlen >= 3; inlen -= 3, in += 3)
    {
        /* update output length and check overflow */
        outlen += 4;
        if ((outlen >= maxlen) && maxlen)
        {
            /* use >= because there must have a '\0' */
            *out_org = '\0';
            return UTL_BASE64_OUTPUT_OVERFLOW;
        }

        if ((*out++ = ENCODE64((in[0] >> 2) & 0x3F)) == BAD)
        {
            *out_org = '\0';
            return UTL_BASE64_WRONG_FORMAT;
        }

        if ((*out++ = ENCODE64(((in[0] << 4) & 0x30) | ((in[1] >> 4) & 0x0F))) == BAD)
        {
            *out_org = '\0';
            return UTL_BASE64_WRONG_FORMAT;
        }

        if ((*out++ = ENCODE64(((in[1] << 2) & 0x3C) | ((in[2] >> 6) & 0x03))) == BAD)
        {
            *out_org = '\0';
            return UTL_BASE64_WRONG_FORMAT;
        }

        if ((*out++ = ENCODE64(in[2] & 0x3F)) == BAD)
        {
            *out_org = '\0';
            return UTL_BASE64_WRONG_FORMAT;
        }
    }

    /* encode tail-fragment if exist */
    if (inlen > 0)
    {
        char fragment;

        /* update output length and check overflow */
        outlen += 4;
        if ((outlen >= maxlen) && maxlen)
        {
            *out_org = '\0';
            return UTL_BASE64_OUTPUT_OVERFLOW;
        }

        if ((*out++ = ENCODE64((in[0] >> 2) & 0x3F)) == BAD)
        {
            *out_org = '\0';
            return UTL_BASE64_WRONG_FORMAT;
        }

        fragment = (in[0] << 4) & 0x30;
        if (inlen > 1)
        {
            fragment |= (in[1] >> 4) & 0x0F;
        }

        if ((*out++ = ENCODE64(fragment)) == BAD)
        {
            *out_org = '\0';
            return UTL_BASE64_WRONG_FORMAT;
        }

        if (inlen < 2)
        {
            *out++ = '=';
        }
        else
        {
            if ((*out++ = ENCODE64((in[1] << 2) & 0x3C)) == BAD)
            {
                *out_org = '\0';
                return UTL_BASE64_WRONG_FORMAT;
            }
        }

        *out++ = '=';
    }

    /* terminate the output string */
    *out = '\0';
    return outlen;
}


/**
 *   @Description: CRC16Ð£Ñé
 *   @param data_arr - »º´æÇø
 *   @param data_len - ´ýÐ£ÑéÊý¾Ý³¤¶È
 *   @return £ºCRC16Ð£ÑéÖµ
 */
uint16_t UTL_Crc16CalcCCITT(uint8_t *data_arr, uint16_t data_len)
{
    uint16_t crc16, i;

    crc16 = 0;
    for (i = 0; i < data_len; i++)
    {
        crc16  = (uint16_t)((crc16 >> 8) | (crc16 << 8));
        crc16 ^= data_arr[i];
        crc16 ^= (uint16_t)((crc16 & 0xFF) >> 4);
        crc16 ^= (uint16_t)((crc16 << 8) << 4);
        crc16 ^= (uint16_t)(((crc16 & 0xFF) << 4) << 1);
    }

    return crc16;
}

/*******************************************************************************
* Function Name  : init_crc32_tab
* Description    : get the init crc table
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void UTL_Crc32TabInit( void ) 
{
	int i, j;
	uint32_t u32Crc;

	memset(auiCrc32,0, sizeof(auiCrc32));
	
	for (i=0; i<256; i++)
	{
		u32Crc = (unsigned long)i;
		for (j=0; j<8; j++) 
		{
			if (u32Crc & 0x00000001L)
				u32Crc = (u32Crc >> 1) ^ POLY;
			else      
				u32Crc = u32Crc >> 1;
		}
		auiCrc32[i] = u32Crc;
	}
}

/*******************************************************************************
* Function Name  : get_crc32
* Description    : get the 32-bit crc of a buf
* Input          : u32_crcinit:a 32-bit init crc ;p_buf:the buf to calc ,
					u32_buf_size:the size fo the buf
* Output         : None
* Return         : a 32-bit crc
*******************************************************************************/
uint32_t UTL_Crc32Calc(uint32_t u32Crcinit, uint8_t * pBuf ,uint32_t u32BufSize)
{
	uint32_t u32Crc = u32Crcinit ^ 0xffffffff;
 
	UTL_Crc32TabInit();
	while (u32BufSize--)
		u32Crc = (u32Crc >> 8) ^ auiCrc32[(u32Crc & 0xff) ^ *pBuf++];
 
	return u32Crc ^ 0xffffffff;
}


/***********************************************************
* @Function:       // º¯ÊýÃû³Æ
* @Description:    // º¯Êý¹¦ÄÜ¡¢ÐÔÄÜµÈµÄÃèÊö
* @Input:          // 1.ÊäÈë²ÎÊý1£¬ËµÃ÷£¬°üÀ¨Ã¿¸ö²ÎÊýµÄ×÷ÓÃ¡¢È¡ÖµËµÃ÷¼°²ÎÊý¼ä¹ØÏµ
* @Input:          // 2.ÊäÈë²ÎÊý2£¬ËµÃ÷£¬°üÀ¨Ã¿¸ö²ÎÊýµÄ×÷ÓÃ¡¢È¡ÖµËµÃ÷¼°²ÎÊý¼ä¹ØÏµ
* @Output:         // 1.Êä³ö²ÎÊý1£¬ËµÃ÷
* @Return:         // º¯Êý·µ»ØÖµµÄËµÃ÷
* @Others:         // ÆäËüËµÃ÷
***********************************************************/
void UTL_ToUpper(char *str, uint16_t len)
{
    uint16_t i = 0;

    for (i = 0; i <= len; i++)
    {
        if ((str[i] >= 'a') && (str[i] <= 'z'))
        {
            str[i] = str[i] - 32;
        }
        else
        {
            continue;/*a[i]=a[i]+32; */
        }
    }
}


/***********************************************************
* @Function:       // º¯ÊýÃû³Æ
* @Description:    // º¯Êý¹¦ÄÜ¡¢ÐÔÄÜµÈµÄÃèÊö
* @Input:          // 1.ÊäÈë²ÎÊý1£¬ËµÃ÷£¬°üÀ¨Ã¿¸ö²ÎÊýµÄ×÷ÓÃ¡¢È¡ÖµËµÃ÷¼°²ÎÊý¼ä¹ØÏµ
* @Input:          // 2.ÊäÈë²ÎÊý2£¬ËµÃ÷£¬°üÀ¨Ã¿¸ö²ÎÊýµÄ×÷ÓÃ¡¢È¡ÖµËµÃ÷¼°²ÎÊý¼ä¹ØÏµ
* @Output:         // 1.Êä³ö²ÎÊý1£¬ËµÃ÷
* @Return:         // º¯Êý·µ»ØÖµµÄËµÃ÷
* @Others:         // ÆäËüËµÃ÷
***********************************************************/
void UTL_ToLower(char *str, uint16_t len)
{
    uint16_t i = 0;

    for (i = 0; i <= len; i++)
    {
        if ((str[i] >= 'a') && (str[i] <= 'z'))
        {
            str[i] = str[i] + 32;
        }
        else
        {
            continue;/* */
        }
    }
}

/*******************************************************************************
* Function Name      : UTL_SubStr
* Description	     : cut the sub string between string cStart and string cEnd
* Input 		     : cSrc: the string to be cut, cStart: left sub str, cEnd: right sub str
* Output		     : cDest: the target sub str
* Return		     : error code on error, 0 on success.
*******************************************************************************/
int32_t UTL_SubStr(const char * pSrc, const char * pStart, const char * pEnd, char **pDest)
{
    char *pStartTmp = NULL;
    char *pEndTmp = NULL;
    int32_t iLen = 0;

    if (NULL == pSrc || NULL == pStart || NULL == pEnd || NULL == pDest)
    {
        return -1;
    }

    if (strlen(pSrc) <= strlen(pStart) + strlen(pEnd))
    {
        return -1;
    }

    pStartTmp = strstr(pSrc, pStart);
    if (NULL == pStartTmp)
    {
        return -1;
    }

    pEndTmp = strstr(pSrc, pEnd);
    if (NULL == pEndTmp)
    {
        return -1;
    }
    
    iLen = strlen(pStartTmp) - strlen(pEndTmp) - strlen(pStart);
    if (iLen <= 0)
    {
        return -1;
    }

    *pDest = pStartTmp + strlen(pStart);
    *(*pDest + iLen) = '\0';

    return 0;
}


/**
 *
 *
 */
uint16_t UTL_NTOHS(uint16_t usValue)
{
    if (true == UTL_IsLittleEndian())
    {
        return _SWAP16(usValue);
    }

    return usValue;
}

/**
 *
 *
 */
uint16_t UTL_HTONS(uint16_t usValue)
{
    if (true == UTL_IsLittleEndian())
    {
        return _SWAP16(usValue);
    }

    return usValue;
}

/**
 *
 *
 */
uint32_t UTL_NTOHL(uint32_t uiValue)
{
    if (true == UTL_IsLittleEndian())
    {
        return _SWAP32(uiValue);
    }

    return uiValue;
}

/**
 *
 *
 */
uint32_t UTL_HTONL(uint32_t uiValue)
{
    if (true == UTL_IsLittleEndian())
    {
        return _SWAP32(uiValue);
    }

    return uiValue;
}

/**
 *
 *
 */
uint64_t UTL_NTOHLL(uint64_t ulValue)
{
    if (true == UTL_IsLittleEndian())
    {
        ulValue = (((uint64_t)_SWAP32((uint32_t)((ulValue << 32) >> 32))) << 32) | ((uint32_t)_SWAP32((uint32_t)(ulValue >> 32)));
    }

    return ulValue;
}

/**
 *
 *
 */
uint64_t UTL_HTONLL(uint64_t ulValue)
{
    if (true == UTL_IsLittleEndian())
    {
        ulValue = (((uint64_t)_SWAP32((uint32_t)((ulValue << 32) >> 32))) << 32) | ((uint32_t)_SWAP32((uint32_t)(ulValue >> 32)));
    }

    return ulValue;
}

/**
 *
 *
 */
bool UTL_IsLittleEndian(void)
{
    union _endian
    {
	    uint32_t i;
	    char c[4];	
    } u;

    u.i = 0x12345678;

    if (u.c[0] == 0x78)
    {
        return true;
    }

    return false;
}

/************************************** The End Of File **************************************/

